﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MapChart
{
    public partial class MapView : UserControl
    { // 矩阵变换
        private int _average = 6;
        private Bitmap _bitmap = new Bitmap(500, 500, PixelFormat.Format24bppRgb);
        private CompositingQuality _compositingQuality;
        private string _csvPath;
        private InterpolationMode _interpolationMode = InterpolationMode.NearestNeighbor;
        private bool _IsLeftDown;
        private Point _LastPt;
        //格子大小
        private Rectangle _lattice = new Rectangle(0, 0, 6, 6);

        private List<ValueTuple<int, int>> _listValue;
        private Matrix _matrix = new Matrix();
        private Rectangle _rcImg = new Rectangle(0, 0, 0, 0);
        private float _scan = 1;
        private SmoothingMode _smoothingMode;
        private int p;
        private bool source;
        private int x;
        private int y;
        public MapView()
        {
            InitializeComponent();
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            Init();
            this.MouseDown += MappingChart_MouseDown;
            this.MouseMove += MappingChart_MouseMove;
            this.Paint += MappingChart_Paint;
            this.MouseUp += MappingChart_MouseUp;
            this.MouseWheel += MappingChart_MouseWheel;
        }
        private double _dScale = 1.0;
        private void MappingChart_MouseWheel(object sender, MouseEventArgs e)
        {
            Point[] points = new Point[] { e.Location };
            Matrix matrix_Invert = _matrix.Clone();
            matrix_Invert.Invert();
            matrix_Invert.TransformPoints(points);
            Console.WriteLine(points[0]);
            //if (_rcImg.Contains(points[0]))
            {
                double step = 1.2;
                if (e.Delta < 0)
                {
                    step = 1.0 / 1.2;
                }
                _dScale *= step;
                _matrix.Scale((float)step, (float)step);

                Point[] pointse = new Point[] { e.Location };
                matrix_Invert = _matrix.Clone();
                matrix_Invert.Invert();
                matrix_Invert.TransformPoints(pointse);
                _matrix.Translate((pointse[0].X - points[0].X), (pointse[0].Y - points[0].Y));

                Invalidate();
            }

         

        }

        public int Average
        {
            get => _average;
            set => _average = value;
        }

        public Bitmap Bitmap => _bitmap;
        public CompositingQuality CompositingQuality
        {
            get => _compositingQuality;
            set { _compositingQuality = value; Invalidate(); }
        }

        public string CsvPath
        {
            get => _csvPath;
            set
            {
                _csvPath = value;
                var str = System.IO.File.ReadAllLines(Environment.CurrentDirectory + @"\PositionTest.txt");
                _listValue = new List<(int, int)>();

                foreach (var item in str)
                {
                    var tmp = item.Split(',');
                    var x = int.Parse(tmp[0]);
                    var y = int.Parse(tmp[1]);

                    _listValue.Add((x, y));


                }



                drawMapping(_listValue);
            }
        }

        public InterpolationMode InterpolationMode
        {
            get => _interpolationMode;
            set { _interpolationMode = value; Invalidate(); }
        }

        public Rectangle Lattice
        {
            get => _lattice;
            set => _lattice = value;
        }

        public Matrix Matrix => _matrix;
        public float scan
        {
            get => _scan;
            set
            {
                _scan = value;
                Invalidate();
            }
        }
        public SmoothingMode SmoothingMode
        {
            get => _smoothingMode;
            set { _smoothingMode = value; Invalidate(); }
        }

        // 平移图片到窗口的中间
        public void TranslationCenter()
        {
            if (_bitmap == null)
            {
                return;
            }
            Matrix matrixinv = _matrix.Clone();
            matrixinv.Invert();

            // Point[] ptViewCenter = new Point[] { new Point(_.Left + rcBgArea.Width / 2, rcBgArea.Top + rcBgArea.Height / 2) };
            //   matrixinv.TransformPoints(ptViewCenter);

            //   _matrix.Translate(ptViewCenter[0].X - _rcImg.Width / 2, ptViewCenter[0].Y - _rcImg.Height / 2);
            this.Refresh();

        }

        private Matrix OriginMatrix = new Matrix();

        private void Model2()
        {
            _matrix.Invert();
            _matrix.Translate(0, 0);
            CsvPath = "1";
            var xMax = _listValue.Max(a => a.Item1);
            var xMin = _listValue.Min(a => a.Item1);

            var yMax = _listValue.Max(a => a.Item2);
            var yMin = _listValue.Min(a => a.Item2);


            var g = Graphics.FromImage(_bitmap);
            g.Clear(Color.Gray);

            // g.DrawLine(Pens.DeepSkyBlue, 0, 0, 0, _bitmap.Height);

            //g.DrawLine(Pens.DeepSkyBlue, 0, 0, _bitmap.Width, 0);
            var dx = 100; //xMin;
            var dy = (yMax - yMin) * Average;  //(yMax - yMin) * 3 + Average * Average ;

            //  g.TranslateTransform(dx, dy, MatrixOrder.Append);
            OriginMatrix = new Matrix();
            OriginMatrix.Invert();
            OriginMatrix.Translate(dx, dy);
            g.Transform = OriginMatrix;

            // g.DrawLine(Pens.Violet, 0, 0, 0, _bitmap.Height);

            // g.DrawLine(Pens.Violet, 0, 0, _bitmap.Width, 0);


            LrTb(_listValue);

            Task.Run(async () =>
            {
                source = true;

                //OrderByDescending(x =>Math.Sign(x.Index)).ThenBy(x=>Math.Abs(x.Index));
                // var xx = _listValue.OrderByDescending(a =>Math.Sign(a.Item2)).ThenBy(x=> (x.Item2)).ThenBy(y=>y.Item1);

                var xx = _listValue.OrderByDescending(a => (a.Item2)).ThenBy(a => a.Item2).ThenBy(a => a.Item1).ToList();


                var dmDictionary = GroupAndSortCoordinates(xx);//MoveDirection(xx);
                var ix = 0;
                for (int i = 1; i < dmDictionary.Values.Count; i++)
                {
                    var data = dmDictionary[i];

                    foreach (var item in data)
                    {
                        var r = new Random((int)(DateTime.Now.Ticks & 0xffffffff) | (item.Item1));
                        var co = Color.FromArgb(r.Next(0, 255), r.Next(0, 255), r.Next(0, 255));
                        var temprec = new Rectangle(item.Item1 * Average, (item.Item2) * Average, Average, Average);
                        var br = new System.Drawing.SolidBrush(co);
                        var de = _listValue.FirstOrDefault(a => a.Item2 == item.Item2 || a.Item1 == item.Item1);

                        if (item.Item1 == 0 && item.Item2 == 0)
                        {
                            g.FillRectangle(Brushes.Red, temprec);
                        }
                        else if (NoAdjacency(_listValue, item))
                        {
                            g.FillRectangle(Brushes.Blue, temprec);
                        }
                        else
                        {
                            g.FillRectangle(br, temprec);
                        }


                        g.DrawRectangle(Pens.Beige, temprec);

                        var x = p - temprec.X;
                        //var y = temprec.Y > 0 ? -Average:Average;
                        //  Matrix matrixinv = _matrix.Clone();
                        //  matrixinv.Invert();

                        //  _matrix.Translate(x, y);

                        p = temprec.X;


                        //Thread.Sleep(1);
                        this.Invalidate();
                        //  });
                        ix++;
                    }
                    //_bitmap.Save("Emf.Emf", ImageFormat.Emf);
                    this.Invalidate();
                }
                Console.WriteLine(ix);
            });


        }

        private bool NoAdjacency(List<ValueTuple<int, int>> list, (int, int) xyTuple, int indexCircle = 2)
        {
            var b = list.FindIndex(a => a.Item1 == xyTuple.Item1 - indexCircle && a.Item2 == xyTuple.Item2);
            var t = list.FindIndex(a => a.Item1 == xyTuple.Item1 + indexCircle && a.Item2 == xyTuple.Item2);
            var l = list.FindIndex(a => a.Item2 == xyTuple.Item2 - indexCircle && a.Item1 == xyTuple.Item1);
            var r = list.FindIndex(a => a.Item2 == xyTuple.Item2 + indexCircle && a.Item1 == xyTuple.Item1);

            return (b == -1 || t == -1 || l == -1 || r == -1);
        }


        private Dictionary<int, List<ValueTuple<int, int>>> MoveDirection(List<ValueTuple<int, int>> list, int dir = 0, int mainNeedle = 0, int subitem = 4)
        {
            try
            {
                var dictionary = new Dictionary<int, List<ValueTuple<int, int>>>();
                var tmp = new List<ValueTuple<int, int>>();
                var currentRow = list.FirstOrDefault().Item2;
                var index = 0;
                var i = 0;
                var flag = false;
                foreach (var item in list)
                {

                    if (currentRow != item.Item2)
                    {
                        currentRow = item.Item2;

                        index++;

                        if (index % subitem == 0)
                        {
                            flag = !flag;
                        }

                        if (flag)
                        {
                            tmp = tmp.OrderBy(a => a.Item1).ThenBy(b => b.Item2).ToList();
                        }
                        else
                        {
                            tmp = tmp.OrderByDescending(a => a.Item1).ThenBy(b => b.Item2).ToList();
                        }

                        dictionary.Add(index, tmp);

                        tmp = new List<ValueTuple<int, int>>();
                    }
                    tmp.Add(item);


                }

                return dictionary;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }

        private void DrawMainView(Graphics graph)
        {

        }

        private void LrTb(List<ValueTuple<int, int>> list)
        {
            var orIgin = list.OrderByDescending(a => (a.Item2)).ThenBy(a => a.Item2).ThenBy(a => a.Item1);
            var max = orIgin.LongCount();
            var xMax = list.Max(a => a.Item1);
            var xMin = list.Min(a => a.Item1);
            var yMax = list.Max(a => a.Item2);
            var yMin = list.Min(a => a.Item2);

            foreach (var itemTuple in orIgin)
            {

            }


        }
        private Dictionary<int, List<ValueTuple<int, int>>> GroupAndSortCoordinates(List<ValueTuple<int, int>> coordinates, int dir = 0, int mainNeedle = 0, int subitem = 1)
        {
            try
            {
                var groupedCoordinates = coordinates
                    .GroupBy(c => c.Item2)
                    .OrderBy(g => g.Key)
                    .SelectMany((g, index) => (index % subitem == 0 ? g.OrderBy(c => c.Item1) : g.OrderByDescending(c => c.Item1)))
                    .Select((c, index) => new { Index = index / subitem, Coordinate = c })
                    .GroupBy(c => c.Index, c => c.Coordinate)
                    .ToDictionary(g => g.Key + 1, g => g.ToList());

                return groupedCoordinates;
            }
            catch (Exception e)
            {
                Console.WriteLine($"Error: {e.Message}");
                throw;
            }
        }

        private Dictionary<int, List<ValueTuple<int, int>>> MoveDirection2(List<ValueTuple<int, int>> list, int dir = 0, int mainNeedle = 0, int subitem = 4)
        {
            try
            {
                var dictionary = new Dictionary<int, List<ValueTuple<int, int>>>();
                var tmp = new List<ValueTuple<int, int>>();
                var currentRow = list.FirstOrDefault().Item2;
                var index = 0;
                var i = 0;
                var flag = false;
                foreach (var item in list)
                {
                    tmp.Add(item);

                    if (currentRow != item.Item2)
                    {
                        currentRow = item.Item2;
                        if (flag)
                        {
                            tmp = tmp.OrderBy(a => a.Item1).ThenBy(b => b.Item2).ToList();
                        }
                        else
                        {
                            tmp = tmp.OrderByDescending(a => a.Item1).ThenBy(b => b.Item2).ToList();
                            i++;
                        }

                        dictionary.Add(index, tmp);
                        index++;

                        if (index % subitem == 0)
                        {
                            flag = !flag;
                        }

                        tmp = new List<ValueTuple<int, int>>();
                    }


                }
                dictionary.Add(index, tmp);
                return dictionary;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }




        private Object lockObj = new object();
        private void drawMapping(List<ValueTuple<int, int>> list)
        {
            var xMax = list.Max(a => a.Item1);
            var xMin = list.Min(a => a.Item1);

            var yMax = list.Max(a => a.Item2);
            var yMin = list.Min(a => a.Item2);


            _bitmap = new Bitmap(
                (xMax - xMin) * Average * 3,
                (yMax - yMin) * Average * 3,
                PixelFormat.Format24bppRgb);


            //this.Width = _bitmap.Width;
            //this.Height = _bitmap.Height;
            // var g = this.CreateGraphics();
            //  g.TranslateTransform(xMin + _average, (yMax - yMin) * 2 + _average * 6);
            var g = Graphics.FromImage(_bitmap);




            g.Transform = (_matrix);


            _rcImg = new Rectangle(0, 0, _bitmap.Width, _bitmap.Height);
        }

        private void Init()
        {
            _matrix.Reset();
            _IsLeftDown = false;
            _LastPt = new Point();
            //reader = FileIO.FileSystem.OpenTextFieldParser(Application.StartupPath & "\PositionTest.txt")

        }

        private void MappingChart_Load(object sender, EventArgs e)
        {

        }

        private void MappingChart_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                _IsLeftDown = true;

                Point[] points = new Point[] { e.Location };

                Matrix matrix_Invert = _matrix.Clone();

                matrix_Invert.Invert();
                matrix_Invert.TransformPoints(points);

                //if (_rcImg.Contains(points[0]))
                {
                    _LastPt = points[0];

                }

            }
            else
            {
                Invalidate();
            }
        }

        private void MappingChart_MouseMove(object sender, MouseEventArgs e)
        {
            //if (_IsLeftDown)
            //{
            //    Point[] points = new Point[] { e.Location };
            //     Matrix matrix_Invert = _matrix.Clone();
            //    _matrix.Invert();
            //     matrix_Invert.TransformPoints(points);

            //    _matrix.Translate(((points[0].X - _LastPt.X)), ((points[0].Y - _LastPt.Y)));

            //    this.Invalidate();
            //    propertyGrid1.SelectedObject = _matrix;
            //}

            if (_IsLeftDown)
            {
                Point[] points = new Point[] { e.Location };
                Matrix matrix_Invert = _matrix.Clone();

                matrix_Invert.Invert();
                matrix_Invert.TransformPoints(points);

                _matrix.Translate(points[0].X - _LastPt.X, points[0].Y - _LastPt.Y);

                // 修正矩阵，避免累积误差
                //_matrix.Multiply(matrix_Invert);

                this.Invalidate();
              
            }



        }

        private void MappingChart_MouseUp(object sender, MouseEventArgs e)
        {
            _IsLeftDown = false;

        }
        private void MappingChart_Paint(object sender, PaintEventArgs e)
        {
            var sw = Stopwatch.StartNew();

            if (_bitmap != null)
            {
                // var rect = new Rectangle(new Point(), _bitmap.Size);
                lock (lockObj)
                {
                    e.Graphics.CompositingQuality = CompositingQuality;
                    e.Graphics.SmoothingMode = SmoothingMode == SmoothingMode.Invalid ? SmoothingMode.AntiAlias : SmoothingMode;
                    e.Graphics.InterpolationMode = InterpolationMode == InterpolationMode.Invalid ? InterpolationMode.Bicubic : InterpolationMode;

                    // 双缓冲绘图
                    //Bitmap bmpChartView = new Bitmap(this.Width, this.Height);
                    //Graphics bmpChartView_g = Graphics.FromImage(bmpChartView);


                    e.Graphics.Transform = _matrix;

                    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
                    e.Graphics.ScaleTransform(scan, scan, MatrixOrder.Append);

                    e.Graphics.DrawImageUnscaled(_bitmap, 0, 0);

                }
                //     Bitmap bitImg = new Bitmap(rcBgArea.Width, rcBgArea.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                // Graphics bitImg_g = Graphics.FromImage(bitImg);
                //graph.Transform = _matrix;

                e.Graphics.DrawLine(Pens.Red, this.Width / 2, 0, this.Width / 2, Height);
                e.Graphics.DrawLine(Pens.Red, 0, Height / 2, this.Width, Height / 2);


                //graph.DrawImage(bitImg, rcBgArea.Left, rcBgArea.Top, bitImg.Width, bitImg.Height);

                e.Graphics.FillRectangle(Brushes.White, new RectangleF(_LastPt.X, _LastPt.Y, 200, 150));
                e.Graphics.DrawString(
                    $"{_matrix.OffsetX}_{_matrix.OffsetY}\r\n" +
                    $"{_LastPt.X}_{_LastPt.Y}\r\n" +
                    $"{Math.Floor((_LastPt.X - OriginMatrix.OffsetX) / Average)}_{Math.Floor((_LastPt.Y - OriginMatrix.OffsetY) / Average)}\r\n" +
                    $"{sw.ElapsedMilliseconds} ms"
                    , new Font("宋体", 28), Brushes.Red, _LastPt);

                DrawMainView(e.Graphics);
            }
        }
    }
}
